-
-
Notifications
You must be signed in to change notification settings - Fork 150
Reinitialize serial buffer on every read to avoid concurrent rewrite #481
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
buffered_ch was being rewritten with data being read on a later Read() Attention: this implementation "leaks" (ch will be garbage collected every time) Please profile the memory usage before merging
I'm letting it run reading the serial monitor without issues or memory growing. Looks fine to me |
Did you try some VERY FAST print like |
@facchinm can you elaborate on how this fix works exactly? From looking at the code, I cannot see why the original code would be wrong, or why the new code really changes anything (admittedly, I do not remember all details around how golang's slices and arrays work exactly). |
@matthijskooijman me neither, but what I experienced was:
... after Read() is executed again, roughly 1 times out of 10 ...
I thought it was a concurrency issue but it may be more subtle (it surely is) |
fmt.Println(buffered_ch.Bytes()) // <- now it holds ch[:previous_n] Ah, so you're saying that this holds the bytes from the current I suspect that that this:
does not actually copy values into However, looking at the docs for |
Is this utf8 conversion really needed here? I would let the agent just send the raw data over the wire and delegate the utf8 conversion to the serial monitor, this would simplify a lot the copy-loop. Also from the serial monitor we can receive basically everything, even non-UTF8 chars. |
Good point. I think this code might still stem from the serial-port-json-server where the agent was originally based on (I think?), which actually did some processing of commands in the server as well (so that probably needed this processing). I think there might be some other indirections in the (serial) processing that are not really needed anymore. |
@cmaglie the communication layer is plain text so no binary data can be sent over that channel. I think interpreting the output and not sending raw data should be kept but of course if there's a better fix let's do it 😄 |
What layer is that exactly? Websockets? I think those can be binary as well? Alternatively, you could encode the data using some encoding (base64, or something that only encodes bytes > 127). Adding encoding does require changes on both sides, of course. |
asking our master of Go @matteosuppo, please advise. |
also if @masci could review this would be awesome. |
I think that changing the encoding is out of scope for this fix, especially since it's urgent. Regarding the performance of instantiating a new ch or fixing the append, that's where some tests and benchmarks would shine. But I would delay them to when we refactor this part. |
@facchinm can we tell jenkins to build this so that we can test also on windows? |
The problem is actually here https://github.com/arduino/arduino-create-agent/pull/481/files#diff-59a5ccbf6d889213033f4a5e627e5aadL115 With this assignment
In this example I've reproduced the case when the final output after 2 readings is truncated https://play.golang.org/p/_qN2a5SHWtW The fix in this PR works since |
your test doesn't reproduce exactly the parsing loop, you forget to insert the utf8 check:
that will save the incomplete utf8 char for the next loop, it will be parsed successfully when the "remainder" is received: https://play.golang.org/p/kfJIYUDB_wU BTW the change in size of |
Ok, I can see how that is not what this code expected. But would it really break? If Eventually, you might end up with a single-byte
|
I'm going to merge so that we can make a test build, and if it works release it. Afterwards we'll allocate some time to better refactor all this |
buffered_ch was being rewritten with data being read on a later Read()
Attention: this implementation "leaks" (ch will be garbage collected every time)
Please profile the memory usage before merging